#pragma once

#include <cstddef>
#include <utility>

/**
 * @brief 第七版本：支持 swap 交换资源。
 *
 * swap 常用于异常安全策略与算法实现，
 * 需要保证交换操作不抛出异常（noexcept）。
 */
template <typename T, typename Deleter = void(*)(T*)>
class UniquePtr {
public:
    using pointer      = T*;
    using element_type = T;
    using deleter_type = Deleter;

    static void default_delete(T* ptr) noexcept {
        delete ptr;
    }

    constexpr UniquePtr() noexcept
        : ptr_(nullptr)
        , deleter_(default_delete) {}

    constexpr UniquePtr(std::nullptr_t) noexcept
        : UniquePtr() {}

    explicit UniquePtr(pointer ptr) noexcept
        : ptr_(ptr)
        , deleter_(default_delete) {}

    ~UniquePtr() {
        reset();
    }

    /**
     * @brief 交换两个 UniquePtr 的资源与删除器。
     *
     * 利用 std::swap 逐一交换成员即可。
     */
    void swap(UniquePtr& other) noexcept {
        std::swap(ptr_, other.ptr_);
        std::swap(deleter_, other.deleter_);
    }

    void reset(pointer ptr = nullptr) noexcept {
        if (ptr_) {
            deleter_(ptr_);
        }
        ptr_ = ptr;
    }

    pointer release() noexcept {
        pointer raw = ptr_;
        ptr_ = nullptr;
        return raw;
    }

    pointer get() const noexcept {
        return ptr_;
    }

    element_type& operator*() const noexcept {
        return *ptr_;
    }

    pointer operator->() const noexcept {
        return ptr_;
    }

    explicit operator bool() const noexcept {
        return ptr_ != nullptr;
    }

private:
    pointer      ptr_;
    deleter_type deleter_;
};

/**
 * @brief 非成员 swap，用于支持 `swap(a, b)` 语法。
 *
 * 通过参数依赖查找（ADL），标准算法在遇到自定义类型时会优先调用此重载。
 */
template <typename T, typename Deleter>
void swap(UniquePtr<T, Deleter>& lhs, UniquePtr<T, Deleter>& rhs) noexcept {
    lhs.swap(rhs);
}